﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace SmartAnswerPlatform.Common
{
    public class MapperHelper
    {
        /// <summary>
        /// 复制单个对象的属性
        /// </summary>
        public static TTarget Copy<TSource, TTarget>(TSource source)
            where TTarget : class, new()
        {
            if (source == null) return null;

            var sourceProps = typeof(TSource).GetProperties()
                .Where(p => p.CanRead && p.GetMethod?.IsPublic == true);

            var targetProps = typeof(TTarget).GetProperties()
                .Where(p => p.CanWrite && p.GetMethod?.IsPublic == true)
                .ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);

            TTarget target = new TTarget();
            foreach (var sourceProp in sourceProps)
            {
                if (targetProps.TryGetValue(sourceProp.Name, out var targetProp))
                {
                    // 检查类型兼容性（包括可空类型处理）
                    if (IsCompatibleType(sourceProp.PropertyType, targetProp.PropertyType))
                    {
                        var value = sourceProp.GetValue(source);
                        targetProp.SetValue(target, value);
                    }
                }
            }
            return target;
        }

        /// <summary>
        /// 复制对象列表
        /// </summary>
        public static List<TTarget> CopyList<TSource, TTarget>(IEnumerable<TSource> sourceList)
            where TTarget : class, new()
        {
            if (sourceList == null) return new List<TTarget>();

            var result = new List<TTarget>();

            // 预获取类型信息提升性能
            var sourceType = typeof(TSource);
            var targetType = typeof(TTarget);

            var sourceProps = sourceType.GetProperties()
                .Where(p => p.CanRead && p.GetMethod?.IsPublic == true)
                .ToArray();

            var targetProps = targetType.GetProperties()
                .Where(p => p.CanWrite && p.GetMethod?.IsPublic == true)
                .ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);

            foreach (var sourceItem in sourceList)
            {
                var targetItem = new TTarget();

                foreach (var sourceProp in sourceProps)
                {
                    if (targetProps.TryGetValue(sourceProp.Name, out var targetProp))
                    {
                        if (IsCompatibleType(sourceProp.PropertyType, targetProp.PropertyType))
                        {
                            var value = sourceProp.GetValue(sourceItem);
                            targetProp.SetValue(targetItem, value);
                        }
                    }
                }

                result.Add(targetItem);
            }

            return result;
        }

        /// <summary>
        /// 高性能列表复制（使用预编译委托）
        /// </summary>
        public static List<TTarget> FastCopyList<TSource, TTarget>(IEnumerable<TSource> sourceList)
            where TTarget : class, new()
        {
            // 获取或创建复制委托
            var copier = ListCopierCache<TSource, TTarget>.Copier;
            return copier(sourceList);
        }

        /// <summary>
        /// 检查类型是否兼容
        /// </summary>
        private static bool IsCompatibleType(Type sourceType, Type targetType)
        {
            // 相同类型
            if (sourceType == targetType) return true;

            // 可空类型处理
            var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
            var underlyingSourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;

            // 基础类型兼容性
            if (underlyingTargetType.IsAssignableFrom(underlyingSourceType))
                return true;

            // 值类型转换
            if (underlyingTargetType.IsValueType && underlyingSourceType.IsValueType)
                return true;

            return false;
        }

        /// <summary>
        /// 缓存列表复制委托
        /// </summary>
        private static class ListCopierCache<TSource, TTarget>
            where TTarget : class, new()
        {
            public static readonly Func<IEnumerable<TSource>, List<TTarget>> Copier = CreateCopier();

            private static Func<IEnumerable<TSource>, List<TTarget>> CreateCopier()
            {
                // 获取类型信息
                var sourceType = typeof(TSource);
                var targetType = typeof(TTarget);

                // 获取属性映射
                var sourceProps = sourceType.GetProperties()
                    .Where(p => p.CanRead && p.GetMethod?.IsPublic == true)
                    .ToArray();

                var targetProps = targetType.GetProperties()
                    .Where(p => p.CanWrite && p.GetMethod?.IsPublic == true)
                    .ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);

                // 创建动态方法
                var method = new DynamicMethod(
                    name: $"{sourceType.Name}_To_{targetType.Name}_Copier",
                    returnType: typeof(List<TTarget>),
                    parameterTypes: new[] { typeof(IEnumerable<TSource>) },
                    restrictedSkipVisibility: true);

                var il = method.GetILGenerator();

                // 创建结果列表
                il.DeclareLocal(typeof(List<TTarget>));
                il.Emit(OpCodes.Newobj, typeof(List<TTarget>).GetConstructor(Type.EmptyTypes));
                il.Emit(OpCodes.Stloc_0);

                // 循环开始
                var loopStart = il.DefineLabel();
                var loopCondition = il.DefineLabel();
                var loopEnd = il.DefineLabel();

                // 获取枚举器
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Callvirt, typeof(IEnumerable<TSource>).GetMethod("GetEnumerator"));
                il.Emit(OpCodes.Stloc_1); // 存储枚举器

                il.BeginExceptionBlock();
                il.MarkLabel(loopCondition);
                il.Emit(OpCodes.Ldloc_1);
                il.Emit(OpCodes.Callvirt, typeof(System.Collections.IEnumerator).GetMethod("MoveNext"));
                il.Emit(OpCodes.Brfalse, loopEnd);

                il.Emit(OpCodes.Ldloc_1);
                il.Emit(OpCodes.Callvirt, typeof(IEnumerator<TSource>).GetProperty("Current").GetMethod);
                il.Emit(OpCodes.Stloc_2); // 存储当前项

                // 创建目标对象
                il.Emit(OpCodes.Newobj, typeof(TTarget).GetConstructor(Type.EmptyTypes));
                il.Emit(OpCodes.Stloc_3); // 存储新对象

                // 复制属性
                foreach (var sourceProp in sourceProps)
                {
                    if (targetProps.TryGetValue(sourceProp.Name, out var targetProp))
                    {
                        if (IsCompatibleType(sourceProp.PropertyType, targetProp.PropertyType))
                        {
                            // 加载目标对象
                            il.Emit(OpCodes.Ldloc_3);

                            // 加载源值
                            il.Emit(OpCodes.Ldloc_2);
                            il.Emit(OpCodes.Callvirt, sourceProp.GetMethod);

                            // 设置目标值
                            il.Emit(OpCodes.Callvirt, targetProp.SetMethod);
                        }
                    }
                }

                // 添加到列表
                il.Emit(OpCodes.Ldloc_0); // 加载列表
                il.Emit(OpCodes.Ldloc_3); // 加载新对象
                il.Emit(OpCodes.Callvirt, typeof(List<TTarget>).GetMethod("Add"));

                il.Emit(OpCodes.Br, loopCondition);
                il.MarkLabel(loopEnd);

                // 返回结果
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Ret);

                return (Func<IEnumerable<TSource>, List<TTarget>>)method.CreateDelegate(
                    typeof(Func<IEnumerable<TSource>, List<TTarget>>));
            }
        }
    }
}
